var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');
var uuid = require('node-uuid');
var fs = require('fs');
var http = require('http');
var Log = require('../utils/logger');
var dbManager = require('../utils/db-manager');
var ObjectID = require('mongodb').ObjectID;

router.use(bodyParser.json()); // for parsing application/json
router.use(bodyParser.urlencoded({extended: true})); // for parsing application/x-www-form-urlencoded

router.restPath = "/test-plan";

router.get('/', function (req, res, next) {
    var logger = Log.getLogger("get test plans");
    //TODO:check the request body
    var collection = dbManager.db.collection('TestPlan');
    collection.find({}).toArray(function(error, result){
        if(error || !result){
            logger.error(error.name + ": " + error.message);
            res.status(404).json({
                name: error.name,
                message: error.message
            });
        }else{
            res.json(result);
        }
    })
});

/* get test plan info */
router.get('/:id', function (req, res, next){
    var tId = req.params.id;
    var logger = Log.getLogger("get test plan with id" );
    logger.info(tId);

    //TODO:check the request body

    var obID;
    try {
        obID = new ObjectID(tId);
    } catch (error) {
        var msg = {
            name:"new ObjectID error",
            message:error.toString()
        };
        logger.error(msg);
        res.status(404).json(msg).end();
        return;
    }
    var testCodeCollection = dbManager.db.collection('TestPlan');
    testCodeCollection.find({_id: obID}).toArray(function(error, result){
        if(error){
            logger.error(error.name + ": " + error.message);
            res.status(404).json({
                name: error.name,
                message: error.message
            });
        }else{
            res.json(result);
        }
    })
});

router.get('/start/:start/end/:end', function(req, res, next){
    var logger = Log.getLogger("get test plan");
    var start = parseInt(req.params.start);
    var end = parseInt(req.params.end);
    //TODO:check the request body
    var testCollection = dbManager.db.collection('TestPlan');
    try{
        var cursor = testCollection.find({}).sort([["createTime",1]]).skip(start).limit(end - start);
        cursor.toArray(function(error, result){
            if(error){
                logger.error(error.name + ": " + error.message);
                res.status(404).json({
                    name: error.name,
                    message: error.message
                });
            }else{
                res.json(result);
            }
        });
    }catch(error){
        logger.error(error.name + ": " + error.message);
        res.status(404).json({
            name: error.name,
            message: error.message
        });
    }
});

router.post('/', function(req, res, next) {
    var logger = Log.getLogger("post test plan");
    //TODO:check the request body
    var testConfig = req.body;
    var test = {
        // testId: uuid.v1(),
        lastRunStatus:"Created",
        lastRunStartTime:Date.parse(new Date()),
        createTime:Date.parse(new Date()),
        name: testConfig.name,
        codeID: testConfig.codeID,
        targetApkID: testConfig.targetApkID
    };


    var codeObjectID;
    var targetObjectID;
    try {
        codeObjectID = new ObjectID(test.codeID);
        targetObjectID = new ObjectID(test.targetApkID);
    } catch (error) {
        var msg = {
            name:"new ObjectID error",
            message:error.toString()
        };
        logger.error(msg);
        res.status(404).json(msg).end();
        return;
    }
    logger.info(test.codeID + " -> " + codeObjectID);
    logger.info(test.targetApkID + " -> " + targetObjectID);

    if(codeObjectID && typeof(codeObjectID)!="undefined" &&
        targetObjectID && typeof(targetObjectID)!="undefined") {
        var contentsBody;
        var findTestCodeSuccess = false;
        var findTargetApkSuccess = false;
        // 获取test code信息
        var codeCollection = dbManager.db.collection('TestCode');
        codeCollection.find({_id: codeObjectID}).limit(1).next(function (err, result) {
            if (err || !result) {
                var error = {};
                error.name = err ? err.name : "GetTestCodeFailed";
                error.message = err ? err.message : "record of " + test.codeID + " couldn't be found.";
                logger.error(error.name + ": " + error.message);
                res.status(404).json({
                    name: error.name,
                    message: error.message
                });
                return;
            } else {
                // TODO(kang): varify the TestCode structure
                findTestCodeSuccess = true;
                logger.info("find in TestCode success");
                contentsBody = result;
                for (var i = 0; i < contentsBody.actionList.length; i++) {
                    contentsBody.actionList[i] = contentsBody.actionList[i].statement;

                }
                test.testCodeName = result.name;
                contentsBody.testName = test.name;
                if(findTargetApkSuccess) {
                    newTestPlan(res,test,contentsBody);
                }
            }
        });

        // 获取target apk信息
        var targetCollection = dbManager.db.collection('TargetApk');
        targetCollection.find({_id: targetObjectID}).limit(1).next(function (err, result) {
            if (err || !result) {
                var error = {};
                error.name = err ? err.name : "GetTargetApkFailed";
                error.message = err ? err.message : "record of " + test.targetApkID + " couldn't be found.";
                logger.error(error.name + ": " + error.message);
                res.status(404).json({
                    name: error.name,
                    message: error.message
                });
                return;
            } else {
                findTargetApkSuccess = true;
                logger.info("find in TargetApk success");
                contentsBody.targetAPKPath = result.fullpath;;
                contentsBody.targetAPKName = result.name;
                if(findTestCodeSuccess) {
                    newTestPlan(res,test,contentsBody);
                }
            }
        });
    } else {
        var msg = {
            name:"codeObjectID or targetObjectID error",
            message:"null or undefined"
        };
        logger.error(msg);
        res.status(404).json(msg).end();
        return;
    }
});

function newTestPlan(res, test, contentsBody) {
    var testCollection = dbManager.db.collection('TestPlan');
    testCollection.insertOne(test).then(function (result) {
        //location header of the response
        contentsBody.testID = test._id;
        createTestProject(res, contentsBody, test._id);
        res.location(router.restPath + "/" + test._id);
        res.status(201).end();
    }, function (error) {
        logger.error("Save to collection:TestPlan failed");
        res.status(405).end();
    });
}

function createTestProject(res, contentsBody, test_id){
    var logger = Log.getLogger("create test project");
    logger.info("requesting java server...");

    logger.info(contentsBody);
    var contents = new Buffer(JSON.stringify(contentsBody));  //fix 中文字符串长度的坑
    logger.info(contents);

    var options = {
        host: "127.0.0.1",
        port: "8890",
        path: '/api/test-project',
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Content-Length' : contents.length
        }
    };

    var reqToService = http.request(options, function(resFromRecordClient){
        resFromRecordClient.on('data', function(data){
            //onSuccess(recordInfo);
            logger.debug(data.toString());
        }).on('end', function(data){
            // updateTestPlanStatus(test_id, "Requested");
        });
    });

    reqToService.on('error', function(err){
        //onError(err);
        logger.error(err.name + ":" + err.message);
    });

    reqToService.write(contents + '\n');
    reqToService.end();
}

function updateTestPlanStatus(test_id, status) {
    var logger = Log.getLogger("update status in db");
    logger.info(test_id + " -> " + status);
    var testPlanCollection = dbManager.db.collection('TestPlan');
    testPlanCollection.updateOne({_id: new ObjectID(test_id)},
        {$set:{'lastRunStatus': status}})
        .then(function(result){
            logger.info("TestPlan updated: "+ test_id);
        }, function (error){
            logger.error("TestPlan update failed"+ test_id);
        });
}

// deprecated?
function generateTestProject(res, testConfig){
    var logger = Log.getLogger("generateTestProject");
    var recordCollection = dbManager.db.collection('TestCode');
    recordCollection.find({name: testConfig.testCodeName}).limit(1).next(function(err, result){
        if(err || !result){
            var error = {};
            error.name = err ? err.name : "GetTestCodeFailed";
            error.message = err ? err.message :  "record of " + testConfig.testCodeName + " couldn't be found.";
            logger.error(error.name + ": " + error.message);
            res.status(404).json({
                name: error.name,
                message: error.message
            });
        }else{
            for(var i = 0; i < result.actionList.length; i++){
                result.actionList[i] = result.actionList[i].statement;
            }
            logger.debug(JSON.stringify(result));
            fs.open("record_" + testConfig.name + ".json", "w", function(err, fd){
                var buf = new Buffer(JSON.stringify(result));
                var c = fs.writeSync(fd, buf, 0, buf.length, 0);
                fs.closeSync(fd);
            });
        }
    });
}

// fixed
router.get('/:testId/config', function (req, res, next){
    var logger = Log.getLogger("get test config");
    //TODO:check the request body
    var testId = req.params.testId;
    var testCollection = dbManager.db.collection('TestPlan');
    // both error and result could be null
    testCollection.find({_id: new ObjectID(testId)}).limit(1).next(function(err, result){
        if(err || !result){
            var error = {};
            error.name = err ? err.name : "GetTestConfigError";
            error.message = err ? err.message :  "test config of " + testId + " couldn't be found.";
            logger.error(error.name + ": " + error.message);
            res.status(404).json({
                name: error.name,
                message: error.message
            });
        }else{
            var config = {
                testCodeName : result.testCodeName,
                name : result.name
            };
            res.json(config);
        }
    });
});
// fixed
router.get('/:testId/summary', function(req, res, next){
    var logger = Log.getLogger("get test summary");
    var testId = req.params.testId;
    //TODO:check the request body
    try {
        var testCollection = dbManager.db.collection('TestPlan');
        testCollection.find({_id: new ObjectID(testId)}).limit(1).next(function (err, result) {
            if (err || !result) {
                var error = {};
                error.name = err ? err.name : "GetTestSummaryError";
                error.message = err ? err.message : "test summary of " + testId + " couldn't be found.";
                logger.error(error.name + ": " + error.message);
                res.status(404).json({
                    name: error.name,
                    message: error.message
                });
            } else {
                var summary = {
                    testId: result._id,
                    lastRunStatus: result.lastRunStatus,
                    lastRunStartTime: result.lastRunStartTime,
                    config: {
                        testCodeName: result.testCodeName,
                        name: result.name
                    },
                    targetApkID: result.targetApkID,
                    reportsID: result.reportsID
                };

                var tcollection = dbManager.db.collection('TargetApk');
                tcollection.find({_id: new ObjectID(summary.targetApkID)}).next(function (error, result) {
                    if (error) {
                        logger.error(error.name + ": " + error.message);
                        res.status(404).json({
                            name: error.name,
                            message: error.message
                        });
                    } else {
                        if(result!=null) {
                            summary.targetApkName = result.name;
                            logger.info(summary.testId);
                            logger.info(summary.targetApkID + " ss");
                        }else{
                            logger.error(summary.testId);
                            logger.error(summary.targetApkID + " ss");
                        }
                        res.json(summary);
                    }
                });
            }
        });
    }catch (error){
        logger.info(error);
    }
});
// fixed
router.get('/:testId/lastrun/progress', function(req, res, next){
    var logger = Log.getLogger("get test progress");
    var testId = req.params.testId;
    //TODO:check the request body
    var testCollection = dbManager.db.collection('TestPlan');
    var progress = {};
    testCollection.find({_id: new ObjectID(testId)}, {fields: {lastRunStatus: 1}}).limit(1).next(function(err, result){
        if(err || !result){
            var error = {};
            error.name = err ? err.name : "GetProgressError";
            error.message = err ? err.message :  "test progress of " + testId + " couldn't be found.";
            logger.error(error.name + ": " + error.message);
            res.status(404).json({
                name: error.name,
                message: error.message
            });
        }else{
            progress.displayString = result.lastRunStatus;
            switch (result.lastRunStatus){
                case "Created":
                    progress.progress = 0;
                    break;
                case "BUILD_FAILED":
                    progress.progress = 0;
                    progress.displayString = "BUILD FAILED";
                    break;
                case "Requested":
                    progress.progress = 25;
                    break;
                case "Result Apk created":
                    progress.progress = 50;
                    progress.displayString = "Generated";
                    break;
                case "Report created":
                    progress.progress = 100;
                    progress.displayString = "Tested";
                    break;
            }
            res.json(progress);
        }
    });
});

// update status
router.get('/:testId/status/:status', function(req, res, next){
    var logger = Log.getLogger("update status");
    var testId = req.params.testId;
    var status = req.params.status;
    logger.info(testId + " -> " + status);
    //TODO:check the request body
    updateTestPlanStatus(testId, status);
    res.status(200).end();
});

module.exports = router;